#include "WearPtr.hpp"
#include <gtest/gtest.h>
#include <string>

/**
 * @brief 辅助类：跟踪对象构造 / 析构次数，验证资源释放时机。
 */
struct Tracker {
    static inline int constructions = 0;
    static inline int destructions  = 0;

    Tracker()  { ++constructions; }
    ~Tracker() { ++destructions;  }

    static void reset() {
        constructions = 0;
        destructions  = 0;
    }
};

/**
 * @brief 测试 1：WearPtr 默认构造应为空，锁定后得到空 SharedPtr。
 *
 * 验证要点：
 * 1. 默认构造的 WearPtr 过期。
 * 2. lock() 返回的 SharedPtr 为空，引用计数为 0。
 */
TEST(WearPtrTest, DefaultConstructedIsExpired) {
    WearPtr<int> wp;
    EXPECT_TRUE(wp.expired());
    auto sp = wp.lock();
    EXPECT_FALSE(sp);
    EXPECT_EQ(sp.use_count(), 0u);
}

/**
 * @brief 测试 2：从 SharedPtr 构造 WearPtr，原对象仍存活时 lock() 应成功。
 *
 * 验证要点：
 * 1. WearPtr 从 SharedPtr 构造后不过期。
 * 2. lock() 返回的 SharedPtr 指向同一对象，引用计数累加。
 */
TEST(WearPtrTest, LockReturnsSharedPtrWhileAlive) {
    auto sp1 = make_shared<std::string>("cpp");
    WearPtr<std::string> wp(sp1);

    EXPECT_FALSE(wp.expired());
    EXPECT_EQ(wp.use_count(), 1u);

    auto sp2 = wp.lock();
    EXPECT_TRUE(sp2);
    EXPECT_EQ(sp2.use_count(), 2u);
    EXPECT_EQ(*sp2, "cpp");
}

/**
 * @brief 测试 3：最后一个 SharedPtr 销毁后，WearPtr 过期，lock() 返回空指针。
 *
 * 验证要点：
 * 1. SharedPtr 离开作用域后 WearPtr 过期。
 * 2. expired() == true，lock() 返回空 SharedPtr。
 */
TEST(WearPtrTest, LockReturnsNullAfterExpiration) {
    WearPtr<int> wp;
    {
        auto sp = make_shared<int>(7);
        wp = WearPtr<int>(sp);
        EXPECT_FALSE(wp.expired());
        EXPECT_EQ(wp.use_count(), 1u);
    }
    EXPECT_TRUE(wp.expired());
    auto locked = wp.lock();
    EXPECT_FALSE(locked);
    EXPECT_EQ(locked.use_count(), 0u);
}

/**
 * @brief 测试 4：多个 WearPtr 可同时观察同一对象，引用计数正确累加。
 *
 * 验证要点：
 * 1. 多个 WearPtr 构造时 weak_count 增加，但 strong_count 不变。
 * 2. lock() 获得的 SharedPtr 共享同一控制块，引用计数正确。
 */
TEST(WearPtrTest, MultipleWearPtrsObserveSameObject) {
    auto sp = make_shared<int>(42);
    WearPtr<int> wp1(sp);
    WearPtr<int> wp2(sp);
    WearPtr<int> wp3 = wp2;

    EXPECT_EQ(wp1.use_count(), 1u);
    EXPECT_FALSE(wp2.expired());
    EXPECT_FALSE(wp3.expired());

    auto sp_from_wp3 = wp3.lock();
    EXPECT_TRUE(sp_from_wp3);
    EXPECT_EQ(sp_from_wp3.use_count(), 2u);  // sp + sp_from_wp3
    EXPECT_EQ(*sp_from_wp3, 42);
}

/**
 * @brief 测试 5：WearPtr 的拷贝 / 移动行为应正确维护弱引用计数。
 *
 * 验证要点：
 * 1. 拷贝构造 +1 弱引用，移动构造不增加计数。
 * 2. 移动后原 WearPtr 置空。
 */
TEST(WearPtrTest, CopyAndMoveSemantics) {
    auto sp = make_shared<int>(10);
    WearPtr<int> wp1(sp);
    WearPtr<int> wp2(wp1);          // 拷贝
    WearPtr<int> wp3(std::move(wp2)); // 移动

    EXPECT_TRUE(wp2.expired());     // 被移动后置空（控制块为 nullptr）
    EXPECT_FALSE(wp3.expired());
    EXPECT_EQ(wp3.use_count(), 1u);

    auto locked = wp3.lock();
    EXPECT_TRUE(locked);
    EXPECT_EQ(*locked, 10);
    EXPECT_EQ(locked.use_count(), 2u);
}

/**
 * @brief 测试 6：WearPtr reset 后释放弱引用，不影响已存在的 SharedPtr。
 *
 * 验证要点：
 * 1. reset() 使 WearPtr 过期。
 * 2. SharedPtr 依旧有效。
 */
TEST(WearPtrTest, ResetReleasesWeakReference) {
    auto sp = make_shared<int>(1);
    WearPtr<int> wp(sp);
    EXPECT_FALSE(wp.expired());

    wp.reset();
    EXPECT_TRUE(wp.expired());
    EXPECT_EQ(wp.use_count(), 0u);
    EXPECT_TRUE(sp);
    EXPECT_EQ(sp.use_count(), 1u);
}

/**
 * @brief 测试 7：控制块在强引用归零后销毁对象，在所有弱引用也释放后才释放自身。
 *
 * 验证要点：
 * 1. 强引用清零时对象析构（Tracker::destructions 累加）。
 * 2. 最后一个 WearPtr 释放后控制块销毁（此处通过析构计数验证）。
 */
TEST(WearPtrTest, ControlBlockLifecycle) {
    Tracker::reset();

    WearPtr<Tracker> wp;
    {
        auto sp = make_shared<Tracker>();
        wp = WearPtr<Tracker>(sp);

        EXPECT_EQ(Tracker::constructions, 1);
        EXPECT_EQ(Tracker::destructions, 0);
    } // sp 析构：对象被销毁，但控制块保留（weak_count > 0）
    EXPECT_EQ(Tracker::destructions, 1);
    EXPECT_TRUE(wp.expired());

    wp.reset(); // 最后一个 WearPtr 释放：控制块也应被销毁
    // 无法直接检测控制块释放，但若未释放会造成内存泄漏，
    // 这里通过析构次数与构造次数相等进行间接验证。
    EXPECT_EQ(Tracker::constructions, Tracker::destructions);
}